#pragma once

// Copyright (c) 2010 Manuel Peinado Gallego <manuel.peinado@gmail.com>
// Distributed under the MIT License

// Vec4.h : interface of the Vec4_ template class
//

#include "Vec3.h"

namespace gx
{
template<class T>
class Vec4_
{
    Vec4_() {}

public:

    T x, y, z, w;

    Vec3 asVec3() const { return Vec3(x, y, z); }

    Vec4_ & operator+=(const Vec4_ & v)
    {
        x += v.x;
        y += v.y;
        z += v.z;
        w += v.w;
        return *this;
    }

    Vec4_ & operator-=(const Vec4_ & v)
    {
        x -= v.x;
        y -= v.y;
        z -= v.z;
        w -= v.w;
        return *this;
    }
    
    friend const Vec4_ operator+(const Vec4_ & u, const Vec4_ & v)
    {
        Vec4_ result = u;
        return result += v;
    }

    friend const Vec4_ operator-(const Vec4_ & u, const Vec4_ & v)
    {
        Vec4_ result = u;
        return result -= v;
    }

    const Vec4_ operator*(T s) const
    {
        return Vec4_(x * s, y * s, z * s, z * s);
    }

    const Vec4_ operator-() const
    {
        return Vec4_(-x, -y, -z, -w);
    }

    Vec4_(T x, T y, T z, T w)
    {
        this->x = x;
        this->y = y;
        this->z = z;
        this->w = w;
    }
    explicit Vec4_(const T * a)
    {
        x = a[0];
        y = a[1];
        z = a[2];
        w = a[3];	
    }
    
    Vec4_(const Vec3 & xyz, T w)
    {
        x = xyz.x;
        y = xyz.y;
        z = xyz.z;
        this->w = w;
    }

    T dot(const Vec4_ & v) const
    {
        // ASSERT(w == 0. && v.w == 0.);
        return x * v.x + y * v.y + z * v.z;
    }

    T norm2() const
    {
        return dot(*this);
    }

    T norm() const
    {
        return sqrt(norm2());
    }

    T dist2(const Vec4_ & v) const
    {
        return (*this - v).norm2();
    }
};

// --------------------------------------------------------------
// Convenience typedefs
// --------------------------------------------------------------

typedef Vec4_<Real> Vec4;
typedef Vec4_<double> Vec4d;
typedef Vec4_<float> Vec4f;

// --------------------------------------------------------------
// Implementation of inlines and templates
// --------------------------------------------------------------

template<class T> Vec4_<T> Dir(T x, T y, T z)
{
    return Vec4_<T>(x, y, z, 0);
}

template<class T> Vec4_<T> Dir(const Vec3_<T> & v)
{
    return Vec4_<T>(v, 0);
}

template<class T> Vec4_<T> Dir(Zero) 
{
    return Vec4_<T>(0, 0, 0, 0);
}

template<class T> Vec4_<T> Pnt(T x, T y, T z)
{
    return Vec4_<T>(x, y, z);
}

template<class T> 
Vec4_<T> Pnt(const Vec3_<T> & v)
{
    return Vec4_<T>(v, 1);
}

template<class T> Vec4_<T> Pnt(Zero) 
{
    return Vec4_<T>(0, 0, 0, 1);
}

template<class T>
Vec3_<T>::Vec3_(const Vec4_<T> & v4)
: x(v4.x), y(v4.y), z(v4.z)
{
}

}


